package com.算法.进程调度模拟;

import javax.swing.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

/**
 * @author zh
 * @date 2024-01-01 15:44
 */
// 进程状态
enum ProcessStatus {
    READY,
    RUNNING,
    BLOCKED
}
class PCB1 {
    String name;
    int priority;
    int arrivalTime;
    int remainingTime;
    int usedCPUTime;
    int IOTime;
    int revolveTime;
    ProcessStatus status;
}
// 队列
class Queue1 {
    private final int MAX_SIZE = 100;
    public PCB1[] items;
    public int front;
    public int rear;
    public int size;

    public Queue1() {
        items = new PCB1[MAX_SIZE];
        front = -1;
        rear = -1;
        size = 0;
    }
    // 判断是否为空
    public boolean isEmpty() {
        return (front == -1 && rear == -1);
    }
    // 判断是否队列已满
    public boolean isFull() {
        return (rear == MAX_SIZE - 1);
    }
    // 出队列
    public void enQueue1(PCB1 data) {
        if (isFull()) {
            System.out.println("队列已满，无法添加数据");
            return;
        }
        if (isEmpty()) {
            front = 0;
        }
        rear++;
        items[rear] = data;
        size++;
    }
    // 进队列
    public PCB1 deQueue1() {
        if (isEmpty()) {
            System.out.println("队列为空");
            return new PCB1(); // 返回一个空 PCB1 表示队列为空
        }
        PCB1 deQueue1dItem = items[front];
        if (front == rear) {
            front = -1;
            rear = -1;
        } else {
            front++;
        }
        size--;
        return deQueue1dItem;
    }
    // 取队列中首个PCB1
    public PCB1 front() {
        if (isEmpty()) {
            System.out.println("队列为空");
            return new PCB1(); // 返回一个空 PCB1 表示队列为空
        }
        return items[front];
    }
    // 取队列中末尾那个PCB1
    public PCB1 rear() {
        if (isEmpty()) {
            System.out.println("队列为空");
            return new PCB1(); // 返回一个空 PCB1 表示队列为空
        }
        return items[rear];
    }
    // 队列大小
    public int size() {
        return size;
    }
    // 清空队列
    public void clear(){
        front = -1;
        rear = -1;
        size = 0;
    }

    // 按大小，从小到大升序对PCB1进行排序
    public void sortBySizeDescending() {
        if (isEmpty() || size() == 1) {
            return;
        }
        // 保存第一个元素
        PCB1 firstItem = items[front];
        // 使用Comparator对从第二个元素到最后一个元素进行排序
        Comparator<PCB1> comparator = Comparator.comparingInt(PCB1 -> PCB1.remainingTime);
        Arrays.sort(items, front + 1, rear + 1, comparator);
        // 将第一个元素放回数组
        items[front] = firstItem;
//        Arrays.sort(items, front, rear + 1, Comparator.comparingInt(PCB1 -> PCB1.remainingTime));
    }

}

public class ProcessManagement {
    private static boolean is_continue_exe() {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("是否继续执行？(Y/N)【输入Y表示继续执行，输入N表示结束执行。】: ");
            String answer = scanner.nextLine().toUpperCase();
            if (answer.equals("Y")) {
                return true;
            } else if (answer.equals("N")) {
                System.out.println("进行结束运行");
                return false;
            } else {
                System.out.println("无效的输入，请重新输入！");
            }
        }
    }
    public static void main(String[] args) {
        while (is_continue_exe()){
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入进程数量：");
            int n = scanner.nextInt();
            Queue1 readyQueue1 = new Queue1();
            Queue1 blockedQueue1 = new Queue1();
            readyQueue1.clear();
            blockedQueue1.clear();
            for (int i = 0; i < n; i++) {
                PCB1 process = new PCB1();
                System.out.println("----------------开始输入第 " + (i + 1) + " 进程的信息------------------");
                System.out.print("进程名称: ");
                process.name = scanner.next();
                System.out.print("优先级 (1-10): ");
                process.priority = scanner.nextInt();
                System.out.print("到达时间: ");
                process.arrivalTime = scanner.nextInt();
                System.out.print("执行时间: ");
                process.remainingTime = scanner.nextInt();
                System.out.println("\n当前进程信息:[进程" + process.name + "] [优先级:" + process.priority + "] [到达时间:" +
                process.arrivalTime + "] [执行时间:" + process.remainingTime + "]\n");
                System.out.println("进程 " + process.name + " 进入就绪队列");
                System.out.println("----------------第 " + (i + 1) + " 进程 " + process.name + " 输入完成--------------------\n");
                process.usedCPUTime = 0;
                process.status = ProcessStatus.READY;
                readyQueue1.enQueue1(process);
            }
            System.out.println("选择算法：【T：时间片轮转S：短作业优先】");
            String f = scanner.next();
            JTextArea textArea = new JTextArea();
            if(f.equals("T") || f.equals("t")){
                TRR(readyQueue1, blockedQueue1,10, textArea);
            }else if(f.equals("S") || f.equals("s")){
                SPF(readyQueue1, blockedQueue1,  textArea);
            }else{
                System.out.println("选择错误！");
            }
        }
    }
    // 先来先进入
    public static void TRR(Queue1 readyQueue1, Queue1 blockedQueue1, int timeSlice, JTextArea textArea) {
        int processNums = readyQueue1.size();
        int count = 0;
        String str = "";
        textArea.append(" |==============================================================================================|\n");
        while (processNums > 0) {
            if (readyQueue1.isEmpty()) {
                continue;
            }
            com.算法.进程调度模拟.PCB1 process = readyQueue1.deQueue1();
//            Random random = new Random();
//            int randomNumber = random.nextInt(5) + 1;
            int randomNumber = 0;
            if (process.remainingTime > timeSlice) {
                process.IOTime += randomNumber;

                process.remainingTime -= timeSlice;
                process.usedCPUTime += timeSlice;
                count += timeSlice;
//                System.out.println("|进程 " + process.name + " 遇到 I/O 请求, 进行堵塞, 更新周转时间, I/O 时间: " + randomNumber + " ms");
                updateTextArea(" | 进程 [ " + process.name + " ] 当前时间片使用完, 更新周转时间, 进入就绪队列尾部 \n",textArea);
                updateTextArea(" |==============================================================================================|\n",textArea);
                blockedQueue1.enQueue1(process);
                try {
                    Thread.sleep(500); // 模拟堵塞时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                com.算法.进程调度模拟.PCB1 process1 = blockedQueue1.deQueue1();
//                System.out.println("进程 " + process.name + " 结束堵塞, 进入就绪队列尾部, IO 时间: " + process1.IOTime + " ms");
//                updateTextArea("| 进程 [ " + process.name + " ] 等待被调用, 周转时间: [ " + process1.revolveTime + " ms ] \n",textArea);
//                updateTextArea("|==============================================================================================|\n",textArea);
                readyQueue1.enQueue1(process1);
            } else {
                process.usedCPUTime += process.remainingTime;

                if (count == 0) {
                    count += process.remainingTime;
                    process.revolveTime = process.remainingTime + process.IOTime - process.arrivalTime;
                } else {
                    count += process.remainingTime;
                    process.revolveTime = count + process.IOTime - process.arrivalTime;
                }
                System.out.println("当前进程 " + process.name + " 执行完成, CPU 使用时间: " + process.usedCPUTime + " ms, 周转时间: " + process.revolveTime + " ms, 当前进程状态: 执行完成！");
                updateTextArea(" | 进程 [ " + process.name + " ] 执行完成, CPU 使用时间: [ " + process.usedCPUTime + " ms ], 周转时间: [ " + process.revolveTime + " ms ], 当前进程状态: 执行完成！\n",textArea);
                updateTextArea(" |==============================================================================================|\n",textArea);
                str += process.name+ "-->";
                processNums--;
            }
        }
        int lastIndex = str.lastIndexOf("-->");
        if (lastIndex != -1) {
            String extractedString = str.substring(0, lastIndex);
            updateTextArea("\n TRR算法 结束顺序为："+extractedString, textArea);
        } else {
            updateTextArea("\n TRR算法 结束顺序为："+str, textArea);
        }
    }
    // 短作业优先
    public static void SPF(Queue1 readyQueue1, Queue1 blockedQueue1, JTextArea textArea) {
        int count = 0;
        String str = "";
        int processNums = readyQueue1.size();
        updateTextArea(" |==============================================================================================|\n",textArea);
        while (processNums > 0) {
            readyQueue1.sortBySizeDescending(); // 按执行时间从小到大排序
            if (readyQueue1.isEmpty()) {
                continue;
            }
            PCB1 process = readyQueue1.deQueue1();
//            System.out.println("count + process.remainingTime:"+Integer.parseInt(String.valueOf(count + process.remainingTime)));
            process.revolveTime = count + process.remainingTime + process.IOTime - process.arrivalTime;
            count += process.remainingTime;
            process.usedCPUTime = process.remainingTime;
            System.out.println(" 进程 " + process.name + " 执行完成, CPU 使用时间: " + process.usedCPUTime + " ms, 周转时间: " + process.revolveTime + " ms, 当前进程状态: 执行完成！");
            updateTextArea(" | 进程 [ " + process.name + " ] 执行完成, CPU 使用时间: [ " + process.usedCPUTime + " ] ms, 周转时间: [ " + process.revolveTime + " ] ms, 当前进程状态: 执行完成！|\n", textArea);
            updateTextArea(" |==============================================================================================|\n",textArea);
            str += process.name;
            processNums--;
        }
        int lastIndex = str.lastIndexOf("-->");
        if (lastIndex != -1) {
            String extractedString = str.substring(0, lastIndex);
            updateTextArea("\n SJF算法 结束顺序为："+extractedString, textArea);
        } else {
            updateTextArea("\n SPF算法 结束顺序为："+str, textArea);
        }
    }
    // 更新文本域
    private static void updateTextArea(String content, JTextArea textArea) {
//        SwingUtilities.invokeLater(() -> {
//        });
        textArea.append(content);

    }
}
